import { StringConstant } from '../constant'
import { StringJoiner } from '../util'
import { ObjectTool } from './ObjectTool'

// noinspection JSUnusedGlobalSymbols
/**
 * StrTool
 * @author 冰凝
 * @date 2022-09-19 09:43:23
 **/
export class StrTool extends StringConstant {

    private static HTTP_ADDRESS = new RegExp('^https?://.*')

    /**
     * 字符串是空? {@code null | undefined | 全是空格的字符串} 被认为是空
     * @param {string} str 待判断字符串
     * @return {boolean}
     */
    public static isEmpty(str?: string): boolean {
        if (ObjectTool.isNull(str)) {
            return true
        }
        // @ts-ignore
        return this.EMPTY === str || String(str).trim().length === 0
    }

    /**
     * 字符串非空? 楼上 {@link #isEmpty} 的取反
     * @param {string} str 待判断字符串
     * @return {boolean}
     */
    public static isNotEmpty(str?: string): boolean {
        return !this.isEmpty(str)
    }

    // noinspection SpellCheckingInspection
    /**
     * 判断字符串非空
     * null, undefined  => true
     * "null", "undefined"  => true (不区分大小写)
     * "  "             => true
     * ""               => true
     * " xxx "          => false
     *
     * 对于非 string 类型, 抛出错误
     * @param {string} str 待检查字符串
     * @return {boolean} 是否为空?
     */
    public static isGenerEmpty(str?: string): boolean {
        if (this.isEmpty(str)) {
            return true
        }
        const s = str!.trim().toLocaleLowerCase()
        return s === this.NULL || s === this.UNDEFINED
    }

    /**
     * 重复
     * @param {string} source
     * @param {number} size
     * @return {string}
     */
    public static repeat(source: string, size: number): string {
        if (this.isEmpty(source) || size <= 0) {
            return this.EMPTY
        }
        const arr = new Array(size)
        for (let i = 0; i < size; i++) {
            arr[i] = source
        }
        return arr.join(this.EMPTY)
    }

    /**
     * 字符串连接
     * TODO: 有点问题
     * @param {string} separator 分隔符
     * @param {string} str 需要连接的字符串的可变参数列表
     * @return {string} 最终连接字符串
     */
    public static join(separator: string, ...str: Array<string>): string {
        return new StringJoiner(separator)
            .addAllNotNull(str)
            .toString()
    }

    /**
     * 对象形式的字符串连接
     * <p>
     * 例:
     * <pre>
     *     const query = StrUtil.joinObject('&', {name: 'test', query: 'other', order: true})
     *     // 输出: name=test$query=other&order=true
     *     console.log(query)
     * </pre>
     *
     * TODO: 有点问题
     *
     * @param {string} separator 每个字符串单元的分隔符
     * @param {Record<PropertyKey, any>} o 对象的 一组 key -> value 为一个字符串单元
     * @param {string} conn 对象 key value 连接字符串, 默认 {@link #EQUAL} (等号)
     * @return {string} 最终连接字符
     */
    public static joinObject(separator: string, o: Record<PropertyKey, any>, conn: string = this.EQUAL): string {
        return new StringJoiner(separator)
            .addAllNotNull(ObjectTool.toArray(o).map(kv => kv.toStr(conn)))
            .toString()
    }

    /**
     * 是HTTP 绝对地址?
     */
    public static isAbsoluteAddress(s: string) {
        return this.HTTP_ADDRESS.test(s)
    }

    /**
     * 不是 HTTP 绝对地址
     */
    public static notAbsoluteAddress(s: string) {
        return !this.HTTP_ADDRESS.test(s)
    }

    /**
     * 对象转 HTTP 查询字符串
     */
    public static toQuery(obj: Record<string, any>): string {
        return Object.keys(obj)
            .map(key => `${ key }=${ obj[key] }`)
            .join('&')
    }

}
